<?php

namespace app\api\controller;

use app\common\controller\Api;
use think\Request;

/**
 * Nginx环境优化的流式输出接口
 */
class NginxStream extends Api
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];

    private $config;
    private $apiKey;

    public function _initialize()
    {
        parent::_initialize();
        $this->config = config('doubao');
        $this->apiKey = $this->config['api_key'];
    }

    /**
     * 流式文本对话 - Nginx环境优化版本
     */
    public function chat(Request $request)
    {
        try {
            // 获取参数
            $question = trim($request->param('question', ''));
            $streamMode = $request->param('stream_mode', 'char');
            
            // 参数验证
            if (empty($question)) {
                $this->streamError('问题内容不能为空');
                return;
            }
            
            // 设置优化的SSE响应头
            $this->setOptimizedHeaders();
            
            // 记录开始
            error_log('Nginx流式处理开始: question=' . $question . ', mode=' . $streamMode);
            
            // 发送开始事件
            $this->sendEvent('start', '开始生成回答...');
            
            // 构建请求数据
            $requestData = [
                'model' => 'doubao-1-5-pro-32k-250115',
                'messages' => [[
                    'role' => 'user', 
                    'content' => $question
                ]],
                'stream' => true,
                'temperature' => 0.7,
                'max_tokens' => 4000
            ];
            
            // 执行流式请求
            $this->executeStreamRequest($requestData, $streamMode);
            
        } catch (\Exception $e) {
            error_log('Nginx流式聊天错误: ' . $e->getMessage());
            $this->sendEvent('error', '系统错误: ' . $e->getMessage());
        }
        
        $this->sendEvent('end', '对话结束');
        exit;
    }
    
    /**
     * 设置优化的响应头 - 针对Nginx + PHP-FPM环境优化
     */
    private function setOptimizedHeaders()
    {
        // 在任何输出之前设置响应头
        header('Content-Type: text/event-stream; charset=utf-8');
        header('Cache-Control: no-cache, no-store, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');
        header('Connection: keep-alive');
        header('Access-Control-Allow-Origin: *');
        header('X-Accel-Buffering: no'); // 禁用Nginx缓冲
        
        // 强制清除所有输出缓冲区
        while (ob_get_level() > 0) {
            ob_end_clean();
        }
        
        // 禁用PHP输出缓冲
        ini_set('output_buffering', 'off');
        ini_set('zlib.output_compression', 'off');
        ini_set('implicit_flush', '1');
        
        // 启用自动刷新
        ob_implicit_flush(true);
        
        // 设置无限制执行时间
        set_time_limit(0);
        
        // 立即刷新输出
        if (function_exists('apache_setenv')) {
            apache_setenv('no-gzip', '1');
        }
        
        // 发送初始数据，确保连接建立
        echo "retry: 1000\n\n";
        flush();
    }
    
    /**
     * 执行流式请求 - Nginx环境优化版本
     */
    private function executeStreamRequest($data, $streamMode = 'char')
    {
        // 记录请求开始
        error_log('Nginx豆包API请求开始: ' . json_encode([
            'url' => $this->config['chat_api_url'],
            'model' => $data['model'] ?? 'unknown'
        ]));
        
        $ch = curl_init();
        
        // 豆包API优化配置
        curl_setopt_array($ch, [
            CURLOPT_URL => $this->config['chat_api_url'],
            CURLOPT_RETURNTRANSFER => false,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($data, JSON_UNESCAPED_UNICODE),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json; charset=utf-8',
                'Authorization: Bearer ' . $this->apiKey,
                'Accept: text/event-stream',
                'Cache-Control: no-cache',
                'Connection: keep-alive'
            ],
            CURLOPT_WRITEFUNCTION => function($ch, $chunk) use ($streamMode) {
                return $this->handleStreamChunk($chunk, $streamMode);
            },
            CURLOPT_TIMEOUT => 300,  // 5分钟超时
            CURLOPT_CONNECTTIMEOUT => 30,  // 连接超时30秒
            CURLOPT_SSL_VERIFYPEER => false,  // 跳过SSL证书验证
            CURLOPT_SSL_VERIFYHOST => false,  // 跳过主机验证
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 3,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_USERAGENT => 'NginxStream/1.0 PHP/' . PHP_VERSION,
            // 流式优化
            CURLOPT_BUFFERSIZE => 1024,  // 1KB缓冲区
            CURLOPT_TCP_NODELAY => true,  // 禁用Nagle算法，提高实时性
            CURLOPT_LOW_SPEED_LIMIT => 1,  // 最低速度1字节/秒
            CURLOPT_LOW_SPEED_TIME => 60   // 60秒内速度低于限制则超时
        ]);
        
        $result = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        $errno = curl_errno($ch);
        
        // 记录请求结果
        error_log('Nginx豆包API请求结束: ' . json_encode([
            'http_code' => $httpCode,
            'curl_error' => $error,
            'curl_errno' => $errno,
            'result' => $result !== false ? 'success' : 'failed'
        ]));
        
        if ($result === false || !empty($error)) {
            $this->sendEvent('error', '连接错误: ' . ($error ?: '未知错误') . ' (errno: ' . $errno . ')');
        } elseif ($httpCode !== 200) {
            $errorMsg = $this->getHttpErrorMessage($httpCode);
            $this->sendEvent('error', "HTTP错误 $httpCode: $errorMsg");
        }
        
        curl_close($ch);
    }
    
    /**
     * 处理流式数据块 - Nginx环境优化版本
     */
    private function handleStreamChunk($chunk, $streamMode = 'char')
    {
        static $buffer = '';
        static $completeContent = '';
        static $messageCount = 0;
        
        $buffer .= $chunk;
        
        // 解析SSE数据流
        $lines = explode("\n", $buffer);
        $buffer = array_pop($lines); // 保留最后一行（可能不完整）
        
        foreach ($lines as $line) {
            $line = trim($line);
            
            // 处理SSE数据行
            if (strpos($line, 'data: ') === 0) {
                $json = substr($line, 6);
                
                // 检查流结束标记
                if ($json === '[DONE]') {
                    error_log('Nginx豆包API流式结束标记接收');
                    $this->finalizeStream($completeContent);
                    return strlen($chunk);
                }
                
                // 解析JSON数据
                $response = json_decode($json, true);
                if (json_last_error() !== JSON_ERROR_NONE) {
                    error_log('Nginx豆包API JSON解析错误: ' . json_last_error_msg() . ', 数据: ' . $json);
                    continue;
                }
                
                // 处理豆包API响应
                if (isset($response['choices'][0]['delta']['content'])) {
                    $content = $response['choices'][0]['delta']['content'];
                    $messageCount++;
                    
                    if (!empty($content)) {
                        // 积累完整内容
                        $completeContent .= $content;
                        
                        // 根据流式模式发送内容
                        $this->sendStreamContent($content, $streamMode);
                    }
                }
                
                // 处理错误情况
                if (isset($response['error'])) {
                    error_log('Nginx豆包API返回错误: ' . json_encode($response['error'], JSON_UNESCAPED_UNICODE));
                    $this->sendEvent('error', '豆包API错误: ' . $response['error']['message']);
                    $this->sendEvent('end', '对话结束');
                    return strlen($chunk);
                }
            }
        }
        
        // 返回处理的数据长度
        return strlen($chunk);
    }
    
    /**
     * 发送流式内容 - 根据模式
     */
    private function sendStreamContent($content, $streamMode = 'char')
    {
        switch ($streamMode) {
            case 'char':
                // 逐字符发送
                $chars = mb_str_split($content, 1, 'UTF-8');
                foreach ($chars as $char) {
                    $this->sendEvent('content', $char);
                    usleep(20000); // 20ms延迟
                }
                break;
                
            case 'word':
                // 逐词发送
                $words = $this->splitIntoWords($content);
                foreach ($words as $word) {
                    if (!empty(trim($word))) {
                        $this->sendEvent('content', $word);
                        usleep(50000); // 50ms延迟
                    }
                }
                break;
                
            case 'chunk':
            case 'complete':
            default:
                // 直接发送整个内容块
                $this->sendEvent('content', $content);
                break;
        }
    }
    
    /**
     * 智能分割内容为词语
     */
    private function splitIntoWords($content)
    {
        // 中文按字符分割，英文按单词分割
        $words = [];
        $currentWord = '';
        
        $chars = mb_str_split($content, 1, 'UTF-8');
        
        foreach ($chars as $char) {
            // 中文字符直接作为一个词
            if (preg_match('/[\x{4e00}-\x{9fff}]/u', $char)) {
                if (!empty($currentWord)) {
                    $words[] = $currentWord;
                    $currentWord = '';
                }
                $words[] = $char;
            }
            // 空格、标点作为分割符
            elseif (preg_match('/[\s\.,;!?]/u', $char)) {
                if (!empty($currentWord)) {
                    $words[] = $currentWord;
                    $currentWord = '';
                }
                $words[] = $char;
            }
            // 英文字符累积
            else {
                $currentWord .= $char;
            }
        }
        
        if (!empty($currentWord)) {
            $words[] = $currentWord;
        }
        
        return $words;
    }
    
    /**
     * 完成流处理
     */
    private function finalizeStream($completeContent)
    {
        error_log('Nginx流完成处理开始');
        
        if (!empty($completeContent)) {
            // 发送处理完成事件
            $this->sendEvent('processed', $completeContent);
            
            // 发送统计信息
            $stats = [
                'total_length' => mb_strlen($completeContent, 'UTF-8'),
                'word_count' => str_word_count($completeContent),
                'processing_time' => time()
            ];
            
            $this->sendEvent('stats', json_encode($stats));
        }
        
        error_log('Nginx流完成处理结束');
    }
    
    /**
     * 获取HTTP错误消息
     */
    private function getHttpErrorMessage($httpCode)
    {
        $errorMessages = [
            400 => '请求参数错误',
            401 => 'API密钥无效或过期',
            403 => '没有访问权限',
            404 => 'API地址不存在',
            429 => '请求过于频繁，请稍后再试',
            500 => '服务器内部错误',
            502 => '网关错误',
            503 => '服务不可用',
            504 => '网关超时'
        ];
        
        return $errorMessages[$httpCode] ?? '未知HTTP错误';
    }
    
    /**
     * 发送SSE事件 - Nginx环境优化版本
     */
    private function sendEvent($event, $data)
    {
        // 构建 SSE 数据格式
        $message = "event: $event\n";
        $message .= "data: " . json_encode(['content' => $data], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n\n";
        
        // 直接输出数据
        echo $message;
        
        // 确保数据发送
        flush();
        
        // 记录发送的数据
        error_log("Nginx已发送SSE事件: {$event}, 数据长度: " . mb_strlen($data, 'UTF-8'));
    }
    
    /**
     * 发送错误并结束 - Nginx环境优化版本
     */
    private function streamError($message)
    {
        // 设置优化的响应头
        $this->setOptimizedHeaders();
        
        echo "event: error\n";
        echo "data: " . json_encode(['content' => $message], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n\n";
        echo "event: end\n";
        echo "data: " . json_encode(['content' => '连接结束'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n\n";
        
        // 确保数据发送
        flush();
        
        exit;
    }
}